package com.egao.common.module.workLog.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.egao.common.core.exception.ParameterException;
import com.egao.common.core.web.JsonResult;
import com.egao.common.core.web.PageParam;
import com.egao.common.core.web.PageResult;
import com.egao.common.manage.CommonRefService;
import com.egao.common.module.system.entity.Role;
import com.egao.common.module.system.entity.User;
import com.egao.common.module.system.entity.UserRole;
import com.egao.common.module.system.mapper.RoleMapper;
import com.egao.common.module.system.mapper.UserMapper;
import com.egao.common.module.system.mapper.UserRoleMapper;
import com.egao.common.module.workLog.entity.AnnualPlan;
import com.egao.common.module.workLog.entity.WorkLog;
import com.egao.common.module.workLog.entity.WorkLogItem;
import com.egao.common.module.workLog.entity.vo.WorkLogItemVO;
import com.egao.common.module.workLog.entity.vo.WorkLogVO;
import com.egao.common.module.workLog.entity.vo.WorkerVO;
import com.egao.common.module.workLog.mapper.AnnualPlanMapper;
import com.egao.common.module.workLog.mapper.WorkLogItemMapper;
import com.egao.common.module.workLog.mapper.WorkLogMapper;
import com.egao.common.module.workLog.service.WorkLogService;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.*;

/**
 * 服务实现类
 *
 * @author shu
 */
@Service
public class WorkLogServiceImpl extends ServiceImpl<WorkLogMapper, WorkLog> implements WorkLogService {

    private CommonRefService refService;

    private WorkLogItemMapper itemMapper;

    private AnnualPlanMapper annualPlanMapper;

    private RoleMapper roleMapper;

    private UserRoleMapper userRoleMapper;

    private UserMapper userMapper;

    @Autowired
    public WorkLogServiceImpl(CommonRefService refService, WorkLogItemMapper itemMapper, AnnualPlanMapper annualPlanMapper,
                              RoleMapper roleMapper, UserRoleMapper userRoleMapper, UserMapper userMapper) {
        this.refService = refService;
        this.itemMapper = itemMapper;
        this.annualPlanMapper = annualPlanMapper;
        this.roleMapper = roleMapper;
        this.userRoleMapper = userRoleMapper;
        this.userMapper = userMapper;
    }

    @Override
    public PageResult<WorkLogVO> listPage(PageParam<WorkLog> page) {
        QueryWrapper<WorkLog> wrapper = new QueryWrapper<>();
        wrapper.ge(page.getPageData().get("beginDate") != null, "update_time", page.getPageData().get("beginDate"));
        wrapper.lt(page.getPageData().get("endDate") != null, "update_time", page.getPageData().get("endDate"));
        wrapper.eq(page.getPageData().get("userId") != null, "user_id", page.getPageData().get("userId"));
        return new PageResult<>(models2vos(this.page(page, wrapper).getRecords()), page.getTotal());
    }

    public List<WorkLogVO> models2vos(List<WorkLog> models) {
        List<WorkLogVO> vos = new LinkedList<>();
        List<Integer> ids = new LinkedList<>();
        models.forEach(model -> {
            WorkLogVO vo = new WorkLogVO();
            BeanUtils.copyProperties(model, vo);
            vos.add(vo);
            if (!ids.contains(model.getUserId())) {
                ids.add(model.getUserId());
            }
            if (!ids.contains(model.getCreateUser())) {
                ids.add(model.getCreateUser());
            }
            if (!ids.contains(model.getUpdateUser())) {
                ids.add(model.getUpdateUser());
            }
        });
        Map<Integer, User> map = refService.refUser(ids);
        vos.forEach(vo -> {
            if (map.get(vo.getUserId()) != null) {
                vo.setUserCode(map.get(vo.getUserId()).getUsername());
                vo.setUserName(map.get(vo.getUserId()).getName());
            }
            if (map.get(vo.getCreateUser()) != null) {
                vo.setCreateUserCode(map.get(vo.getCreateUser()).getUsername());
                vo.setCreateUserName(map.get(vo.getCreateUser()).getName());
            }
            if (map.get(vo.getUpdateUser()) != null) {
                vo.setUpdateUserCode(map.get(vo.getUpdateUser()).getUsername());
                vo.setUpdateUserName(map.get(vo.getUpdateUser()).getName());
            }
        });
        return vos;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult insertWorkLog(WorkLogVO param) {
        if (param == null || param.getUserDepartment() == null) {
            throw new ParameterException("参数对象为空");
        }
        WorkLog model = new WorkLog();
        BeanUtils.copyProperties(param, model);
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        User curUser = (User) authentication.getPrincipal();
        model.setUserId(curUser.getUserId());
        model.setCreateUser(curUser.getUserId());
        model.setUpdateUser(curUser.getUserId());
        baseMapper.insert(model);
        param.getItems().forEach(item -> {
            WorkLogItem workLogItem = new WorkLogItem();
            item.setUserDepartment(model.getUserDepartment());
            item.setLogId(model.getId());
            item.setUserId(model.getUserId());
            BeanUtils.copyProperties(item, workLogItem);
            itemMapper.insert(workLogItem);
        });
        return read(model.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult updateWorkLog(WorkLogVO param) {
        if (param == null || param.getUserDepartment() == null || param.getId() == null) {
            throw new ParameterException("参数对象为空");
        }
        WorkLog model = new WorkLog();
        BeanUtils.copyProperties(param, model);
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        User curUser = (User) authentication.getPrincipal();
        model.setUpdateUser(curUser.getUserId());
        model.setUpdateTime(new Date());
        baseMapper.updateById(model);
        param.getItems().forEach(item -> {
            WorkLogItem workLogItem = new WorkLogItem();
            item.setUserId(model.getUserId());
            item.setUserDepartment(model.getUserDepartment());
            BeanUtils.copyProperties(item, workLogItem);
            if (item.getId() == null) {
                itemMapper.insert(workLogItem);
            } else {
                item.setUpdateTime(model.getUpdateTime());
                itemMapper.updateById(workLogItem);
            }
        });
        if (param.getDelItems() != null && param.getDelItems().size() > 0) {
            itemMapper.deleteBatchIds(param.getDelItems());
        }
        return read(model.getId());
    }

    @Override
    @Transactional
    public JsonResult deleteWorkLog(Integer[] ids) {
        if (ids == null) {
            throw new ParameterException("参数对象为空");
        }

        if (ids != null || ids.length > 0) {
            baseMapper.deleteBatchIds(Arrays.asList(ids));
            QueryWrapper<WorkLogItem> wrapper = new QueryWrapper<>();
            wrapper.in("log_id", ids);
            itemMapper.delete(wrapper);
        }
        return JsonResult.ok("删除成功");
    }

    @Override
    public JsonResult read(Integer id) {
        if (id == null) {
            throw new ParameterException("参数对象为空");
        }

        WorkLog model = baseMapper.selectById(id);
        if (model != null) {
            WorkLogVO vo = new WorkLogVO();
            BeanUtils.copyProperties(model, vo);
            LinkedList<Integer> ids = new LinkedList<>();
            if (!ids.contains(model.getUserId())) {
                ids.add(model.getUserId());
            }
            if (!ids.contains(model.getCreateUser())) {
                ids.add(model.getCreateUser());
            }
            if (!ids.contains(model.getUpdateUser())) {
                ids.add(model.getUpdateUser());
            }
            Map<Integer, User> map = refService.refUser(ids);
            model2vo(vo, map);
            QueryWrapper<WorkLogItem> wrapper = new QueryWrapper<>();
            wrapper.eq("log_id", id);
            List<WorkLogItemVO> items = items2vos(itemMapper.selectList(wrapper));
            vo.setItems(items);
            return JsonResult.ok().setData(vo);
        }
        return JsonResult.ok().setData(model);
    }

    public Map<Integer, AnnualPlan> refPlan(List<Integer> ids) {
        Map<Integer, AnnualPlan> map = new HashMap<Integer, AnnualPlan>();
        if (ids != null && ids.size() > 0) {
            QueryWrapper<AnnualPlan> wrapper = new QueryWrapper<>();
            wrapper.in("id", ids);
            List<AnnualPlan> models = annualPlanMapper.selectList(wrapper);
            for (AnnualPlan model : models) {
                map.put(model.getId(), model);
            }
        }
        return map;
    }

    public List<WorkLogItemVO> items2vos(List<WorkLogItem> models) {
        List<WorkLogItemVO> vos = new LinkedList<>();
        List<Integer> ids = new LinkedList<>();
        models.forEach(model -> {
            WorkLogItemVO vo = new WorkLogItemVO();
            BeanUtils.copyProperties(model, vo);
            vos.add(vo);
            if (!ids.contains(model.getAnnualPlanId())) {
                ids.add(model.getAnnualPlanId());
            }
        });
        Map<Integer, AnnualPlan> map = refPlan(ids);
        vos.forEach(vo -> {
            if (map.get(vo.getAnnualPlanId()) != null) {
                vo.setAnnualPlanTitle(map.get(vo.getAnnualPlanId()).getTitle());
                vo.setPlanStartTime(map.get(vo.getAnnualPlanId()).getStartTime());
                vo.setPlanEndTime(map.get(vo.getAnnualPlanId()).getEndTime());
            }
        });
        return vos;
    }

    private void model2vo(WorkLogVO vo, Map<Integer, User> map) {
        if (map.get(vo.getUserId()) != null) {
            vo.setUserCode(map.get(vo.getUserId()).getUsername());
            vo.setUserName(map.get(vo.getUserId()).getName());
        }
        if (map.get(vo.getCreateUser()) != null) {
            vo.setCreateUserCode(map.get(vo.getCreateUser()).getUsername());
            vo.setCreateUserName(map.get(vo.getCreateUser()).getName());
        }
        if (map.get(vo.getUpdateUser()) != null) {
            vo.setUpdateUserCode(map.get(vo.getUpdateUser()).getUsername());
            vo.setUpdateUserName(map.get(vo.getUpdateUser()).getName());
        }
    }

    @Override
    public JsonResult summary(String date, Integer userId) {
        if (StrUtil.isBlank(date)) {
            throw new ParameterException("参数对象为空");
        }
        LocalDate inputDate = LocalDate.parse(date);
        LocalDate beginDay = inputDate.with(DayOfWeek.MONDAY);
        LocalDate endDay = inputDate.with(DayOfWeek.SUNDAY).plusDays(1);
        Map<Integer, Map<Integer, List<WorkLogItemVO>>> map = summaryMap(beginDay, endDay, userId);
        return JsonResult.ok().setData(map);
    }

    @Override
    public JsonResult summaryAll(String beginDate, String endDate, Integer userId) {
        LocalDate beginDay = beginDate == null ? null : LocalDate.parse(beginDate);
        LocalDate endDay = endDate == null ? null : LocalDate.parse(endDate);
        Map<Integer, Map<Integer, List<WorkLogItemVO>>> map = summaryMap(beginDay, endDay, userId);
        return JsonResult.ok().setData(map);
    }

    private @NotNull Map<Integer, Map<Integer, List<WorkLogItemVO>>> summaryMap(LocalDate beginDate, LocalDate endDate, Integer userId) {
        QueryWrapper<WorkLogItem> wrapper = new QueryWrapper<>();
        wrapper.ge(beginDate != null, "update_time", beginDate);
        wrapper.lt(endDate != null, "update_time", endDate);
        wrapper.eq(userId != null, "user_id", userId);
        wrapper.orderByAsc("type", "annual_plan_id", "update_time");
        List<WorkLogItemVO> items = items2vos(itemMapper.selectList(wrapper));
        Map<Integer, Map<Integer, List<WorkLogItemVO>>> map = new HashMap<>();
        List<Integer> ids = new LinkedList<>();
        items.forEach(item -> {
            if (!ids.contains(item.getUserId())) {
                ids.add(item.getUserId());
            }
        });
        Map<Integer, User> refUser = refService.refUser(ids);
        items.forEach(item -> {
            String content = item.getContent();
            StringBuffer sb = new StringBuffer();
            sb.append(content);
            if (item.getRemark() != null && StringUtils.isNotBlank(item.getRemark())) {
                sb.append("(").append(item.getRemark()).append(")");
            }
            if (refUser.get(item.getUserId()) != null) {
                sb.append("[").append(refUser.get(item.getUserId()).getName()).append("]");
            }
            item.setContent(sb.toString());
            map.computeIfAbsent(item.getUserDepartment(), k -> new HashMap<>())
                    .computeIfAbsent(item.getAnnualPlanId(), k -> new ArrayList<>())
                    .add(item);
        });
        return map;
    }

    @Override
    public JsonResult selectWorker(String con) {
        Role role = roleMapper.selectOne(new QueryWrapper<Role>().eq("role_name", "就业中心"));
        List<UserRole> userRoles = userRoleMapper.selectList(new QueryWrapper<UserRole>().eq("role_id", role.getRoleId()));
        List<Integer> ids = new LinkedList<>();
        userRoles.forEach(item -> {
            if (!ids.contains(item.getUserId())) {
                ids.add(item.getUserId());
            }
        });
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.in("user_id", ids);
        if (StringUtils.isNotBlank(con)) {
            wrapper.and(w -> w.like("username", con).or().like("name", con));
        }
        List<User> users = userMapper.selectList(wrapper);
        List<WorkerVO> vos = new LinkedList<>();
        users.forEach(user -> {
            WorkerVO vo = new WorkerVO();
            BeanUtils.copyProperties(user, vo);
            vos.add(vo);
        });
        return JsonResult.ok().setData(vos);
    }

}